package hkust.csit5110.android;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;

/**
 * 
 * record view,the wav generate part and copyright belong to 
 * http://krvarma-android-samples.googlecode.com/svn/trunk/AudioRecorder.2
 * 
 */
public class RecordVoiceView extends Activity {
  private static final int RECORDER_BPP = 16;
  private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
  private static final String AUDIO_RECORDER_FOLDER = "download";
  private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
  private static final int RECORDER_SAMPLERATE = 44100;
  private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
  private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

  private AudioRecord recorder = null;
  private int bufferSize = 0;
  private Thread recordingThread = null;
  private boolean isRecording = false;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.interface2);
    Log.i("===hkust===", "record voice");
    setButtonHandlers();
    enableButtons(false);

    bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
  }

  private void setButtonHandlers() {
    ((Button) findViewById(R.id.starecbtn)).setOnClickListener(btnClick);
    ((Button) findViewById(R.id.stprecbtn)).setOnClickListener(btnClick);
  }

  private void enableButton(int id, boolean isEnable) {
    ((Button) findViewById(id)).setEnabled(isEnable);
  }

  private void enableButtons(boolean isRecording) {
    enableButton(R.id.starecbtn, !isRecording);
    enableButton(R.id.stprecbtn, isRecording);
  }

  private String getFilename() {
    String filepath = Environment.getExternalStorageDirectory().getPath();
    File file = new File(filepath, AUDIO_RECORDER_FOLDER);

    if (!file.exists()) {
      file.mkdirs();
    }

    return (file.getAbsolutePath() + "/" + "record" + AUDIO_RECORDER_FILE_EXT_WAV);
  }

  private String getTempFilename() {
    String filepath = Environment.getExternalStorageDirectory().getPath();
    File file = new File(filepath, AUDIO_RECORDER_FOLDER);

    if (!file.exists()) {
      file.mkdirs();
    }

    File tempFile = new File(filepath, AUDIO_RECORDER_TEMP_FILE);

    if (tempFile.exists())
      tempFile.delete();

    return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE);
  }

  private void startRecording() {
    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize);
    recorder.startRecording();
    isRecording = true;
    recordingThread = new Thread(new Runnable() {
      @Override
      public void run() {
        writeAudioDataToFile();
      }
    }, "AudioRecorder Thread");
    recordingThread.start();
  }

  private void writeAudioDataToFile() {
    byte data[] = new byte[bufferSize];
    String filename = getTempFilename();
    FileOutputStream os = null;
    try {
      os = new FileOutputStream(filename);
    } catch (FileNotFoundException e) {
      Log.e("===hkust===writeAudioDataToFile",e.getMessage());
      e.printStackTrace();
    }

    int read = 0;
    if (null != os) {
      while (isRecording) {
        read = recorder.read(data, 0, bufferSize);
        if (AudioRecord.ERROR_INVALID_OPERATION != read) {
          try {
            os.write(data);
          } catch (IOException e) {
            Log.e("===hkust===writeAudioDataToFile",e.getMessage());
            e.printStackTrace();
          }
        }
      }
      try {
        os.close();
      } catch (IOException e) {
        Log.e("===hkust===writeAudioDataToFile",e.getMessage());
        e.printStackTrace();
      }
    }
  }

  private void stopRecording() {
    if (null != recorder) {
      isRecording = false;
      recorder.stop();
      recorder.release();
      recorder = null;
      recordingThread = null;
    }
    copyWaveFile(getTempFilename(), getFilename());
    deleteTempFile();
  }

  private void deleteTempFile() {
    File file = new File(getTempFilename());
    file.delete();
    Log.i("===hkust===","Delete temp file");
  }

  private void copyWaveFile(String inFilename, String outFilename) {
    FileInputStream in = null;
    FileOutputStream out = null;
    long totalAudioLen = 0;
    long totalDataLen = totalAudioLen + 36;
    long longSampleRate = RECORDER_SAMPLERATE;
    int channels = 2;
    long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels / 8;
    byte[] data = new byte[bufferSize];

    try {
      in = new FileInputStream(inFilename);
      out = new FileOutputStream(outFilename);
      totalAudioLen = in.getChannel().size();
      totalDataLen = totalAudioLen + 36;
      Log.i("===hkust===", "File size: " + totalDataLen);
      WriteWaveFileHeader(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate);
      while (in.read(data) != -1) {
        out.write(data);
      }
      in.close();
      out.close();
    } catch (FileNotFoundException e) {
      Log.e("===hkust===copyWaveFile",e.getMessage());
      e.printStackTrace();
    } catch (IOException e) {
      Log.e("===hkust===copyWaveFile",e.getMessage());
      e.printStackTrace();
    }
  }

  private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate, int channels, long byteRate)
      throws IOException {
    byte[] header = new byte[44];
    header[0] = 'R'; // RIFF/WAVE header
    header[1] = 'I';
    header[2] = 'F';
    header[3] = 'F';
    header[4] = (byte) (totalDataLen & 0xff);
    header[5] = (byte) ((totalDataLen >> 8) & 0xff);
    header[6] = (byte) ((totalDataLen >> 16) & 0xff);
    header[7] = (byte) ((totalDataLen >> 24) & 0xff);
    header[8] = 'W';
    header[9] = 'A';
    header[10] = 'V';
    header[11] = 'E';
    header[12] = 'f'; // 'fmt ' chunk
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    header[16] = 16; // 4 bytes: size of 'fmt ' chunk
    header[17] = 0;
    header[18] = 0;
    header[19] = 0;
    header[20] = 1; // format = 1
    header[21] = 0;
    header[22] = (byte) channels;
    header[23] = 0;
    header[24] = (byte) (longSampleRate & 0xff);
    header[25] = (byte) ((longSampleRate >> 8) & 0xff);
    header[26] = (byte) ((longSampleRate >> 16) & 0xff);
    header[27] = (byte) ((longSampleRate >> 24) & 0xff);
    header[28] = (byte) (byteRate & 0xff);
    header[29] = (byte) ((byteRate >> 8) & 0xff);
    header[30] = (byte) ((byteRate >> 16) & 0xff);
    header[31] = (byte) ((byteRate >> 24) & 0xff);
    header[32] = (byte) (2 * 16 / 8); // block align
    header[33] = 0;
    header[34] = RECORDER_BPP; // bits per sample
    header[35] = 0;
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
    header[40] = (byte) (totalAudioLen & 0xff);
    header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
    header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
    header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
    out.write(header, 0, 44);
  }

  private View.OnClickListener btnClick = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      switch (v.getId()) {
      case R.id.starecbtn: {
        Log.i("===hkust===", "Start Recording");
        enableButtons(true);
        startRecording();
        break;
      }
      case R.id.stprecbtn: {
        Log.i("===hkust===", "Stop Recording!!!");
        enableButtons(false);
        stopRecording();
        Log.i("===hkust===", "Change activity!!!");
        Intent intent = new Intent(RecordVoiceView.this, MatchtView.class);
        startActivity(intent);
        break;
      }
      }
    }
  };
}